# scene.py
#
# Handles a radiosity scene

import xmlscene
from xmlscenefunctions import *
from xmlscenereader import *
from xmlscenewriter import *
from triangulatedpolygon import TriangulatedPolygon
from patch import Patch
from formfactor import *
from transformations import *

import math
import unittest
import sys

def adjustEmissiveObjectRadiosity(object):
    # if an object has emission, bump its radiosity up to at least 
    # that emission level
    r_r, r_g, r_b = extractRGBFromString(object.radiosity)
    e_r, e_g, e_b = extractRGBFromString(object.emission)
    if r_r < e_r:
        r_r = e_r
    if r_g < e_g:
        r_g = e_g
    if r_b < e_b:
        r_b = e_b
    object.set_radiosity(formatRGBAsString(r_r, r_g, r_b))

def initializeEmissiveObjectRadiosities(xml_scene):
    objectdefs = xml_scene.get_head().get_objectdef()
    for objectdef in objectdefs:
        object = objectDefObject(objectdef)
        adjustEmissiveObjectRadiosity(object)

def computeRadiosity(xml_scene, patch_area=1.0, form_factor_threshold=0.0, hemicube_edge=256.0, hemicube_area=512.0, steps=32):
    createGLUTRenderingContext(hemicube_edge)
    initializeEmissiveObjectRadiosities(xml_scene)
    patches = createPatches(xml_scene, applyMacros(xml_scene), patch_area)
    ff_coeffs = createFormFactorCoefficients(hemicube_edge, hemicube_area)
    color_peak = 0.0
    print ""
    print "computeRadiosity()"
    print "  Steps: ", steps
    print "  Patches: ", len(patches)
    for step in range(steps):
        for patch in patches:
            # save the last step's radiosity for computing this step
            patch.saveRadiosity()
        
        for patch in patches:
            sceneAsSeenFromPatch(patch, patches, hemicube_edge)
            patch_scene = glReadPixels(0, 0, int(hemicube_edge*3), int(hemicube_edge*3), GL_RGB, GL_UNSIGNED_BYTE)
            form_factors = formFactorsForPatch(patch, patches, ff_coeffs, hemicube_edge, patch_scene)
            patch.clearFormFactors()
            for ff_key in form_factors.keys():
                patch.addFormFactorForPatch(ff_key, form_factors[ff_key])
            radiosity = patch.computeRadiosity()
            updateColorPeak(color_peak, radiosity)
    xml_computed_scene = convertPatchesToXmlScene(patches)
    return xml_computed_scene

class TestScene(unittest.TestCase):

    def setUp(self):
        self.infile = "./test_scene.xml"
        self.inscene = readScene(self.infile)
        self.precomputed = "./test_scene_precomputed.xml"
        #self.precomputedscene = readScene(self.precomputed)
        self.outfile = "./test_scene_pyrv_computed.xml"

    def test_radiosity_computation(self):
        writeScene(computeRadiosity(readScene("./test_scene_compute_radiosity.xml"), steps=2), self.outfile)
        computed_scene = readScene(self.outfile)
        # TODO: make sure the written scene matches the precomputed scene

if __name__ == '__main__':
    unittest.main()
